﻿using System.Collections.Generic;
using AutoMapper;
using Lucid.ESA.ClientDataSystem.Application.Contracts;
using Lucid.ESA.ClientDataSystem.Application.DataTransferObjects;
using Lucid.ESA.ClientDataSystem.Application.Responses;
using Lucid.ESA.ClientDataSystem.Data.Common;
using Lucid.ESA.ClientDataSystem.Domain.Common;
using Lucid.ESA.ClientDataSystem.Domain.Entities;
using Lucid.ESA.ClientDataSystem.Domain.RepositoryContracts;
using StructureMap;

namespace Lucid.ESA.ClientDataSystem.Application.Implementations
{
    public class ClientService : IClientService
    {
        public Response GetClientById(long id)
        {
            //Load required repositories.
            IClientRepository clientRepository = ObjectFactory.GetInstance<IClientRepository>();

            //Get the entity.
            Client client = clientRepository.GetById(id);

            //Map to DTO.
            Mapper.Reset();
            Mapper.CreateMap<Client, ClientDto>();
            Mapper.CreateMap<Contact, ContactDto>()
                .ForMember(prop => prop.Client, opt => opt.Ignore());
            Mapper.CreateMap<Site, SiteDto>()
                .ForMember(prop => prop.Client, opt => opt.Ignore());
            Mapper.CreateMap<Site, SiteDto>();
            ClientDto clientDto = Mapper.Map<Client, ClientDto>(client);

            //Return DTO in a response object.
            return new GetResponse<ClientDto>(clientDto);
        }

        public Response GetAllClients()
        {
            //Load required repositories.
            IClientRepository clientRepository = ObjectFactory.GetInstance<IClientRepository>();

            //Get the entity.
            List<Client> clients = clientRepository.GetAll();

            //Map to DTO.
            Mapper.Reset();
            Mapper.CreateMap<Client, ClientDto>()
                .ForMember(prop => prop.Sites, opt => opt.Ignore())
                .ForMember(prop => prop.Contacts, opt => opt.Ignore());
            List<ClientDto> clientDtos = Mapper.Map<List<Client>, List<ClientDto>>(clients);

            //Return DTO in a response object.
            return new GetResponse<List<ClientDto>>(clientDtos);
        }

        public Response CreateClient(string name)
        {
            //Load required repositories.
            IClientRepository clientRepository = ObjectFactory.GetInstance<IClientRepository>();

            //Create the entity.
            Client client = Client.Create(name);

            //Validate the entity, and return ValidationErrorResponse if fails.
            ValidationMessageCollection messages = client.Validate();
            if (messages.Count > 0) return new ValidationErrorResponse(messages);

            //Save the entity.
            using(ITransactionProvider transactionProvider = ObjectFactory.GetInstance<ITransactionProvider>())
            {
                transactionProvider.BeginTransaction();
                clientRepository.Save(client);
                transactionProvider.CommitTransaction();
            }

            //Return a successful response (will only get here if no exception is received).
            return new CreateResponse(client.Id.Value);
        }

        public Response EditClient(long clientId, string name)
        {
            //Load required repositories.
            IClientRepository clientRepository = ObjectFactory.GetInstance<IClientRepository>();

            //Get the entity
            Client client = clientRepository.GetById(clientId);

            //Edit the entity.
            client.Edit(name);

            //Validate the entity, and return ValidationErrorResponse if fails.
            ValidationMessageCollection messages = client.Validate();
            if (messages.Count > 0) return new ValidationErrorResponse(messages);

            //Save the entity.
            using (ITransactionProvider transactionProvider = ObjectFactory.GetInstance<ITransactionProvider>())
            {
                transactionProvider.BeginTransaction();
                clientRepository.Save(client);
                transactionProvider.CommitTransaction();
            }

            //Return a successful response (will only get here if no exception is received).
            return new Response(ResponseStatus.Success);
        }
    }
}
